type JSDynamicObject = any;
var log : any [] = [];
var obj : JSDynamicObject = {
    get [Symbol.iterator] () : any {
        log.push ({
            name : "get [Symbol.iterator]"
        });
    },
    get [Symbol.asyncIterator] () : any {
        log.push ({
            name : "get [Symbol.asyncIterator]",
            thisValue : this
        });
        return function (this : JSDynamicObject, ... JSarguments : any []) : JSDynamicObject {
            log.push ({
                name : "call [Symbol.asyncIterator]",
                thisValue : this,
                args : [ ... JSarguments]
            });
            var nextCount : number = 0;
            return {
                name : "asyncIterator",
                get next () : () => JSDynamicObject {
                    log.push ({
                        name : "get next",
                        thisValue : this
                    });
                    return function (this : JSDynamicObject) : JSDynamicObject {
                        log.push ({
                            name : "call next",
                            thisValue : this,
                            args : [ ... JSarguments]
                        });
                        nextCount ++;
                        if (nextCount == 1) {
                            return {
                                name : "next-promise-1",
                                get then () : any {
                                    log.push ({
                                        name : "get next then (1)",
                                        thisValue : this
                                    });
                                    return function (this : JSDynamicObject, resolve : any) : any {
                                        log.push ({
                                            name : "call next then (1)",
                                            thisValue : this,
                                            args : [ ... JSarguments]
                                        });
                                        resolve ({
                                            name : "next-result-1",
                                            get value () : string {
                                                log.push ({
                                                    name : "get next value (1)",
                                                    thisValue : this
                                                });
                                                return "next-value-1";
                                            },
                                            get done () : boolean {
                                                log.push ({
                                                    name : "get next done (1)",
                                                    thisValue : this
                                                });
                                                return false;
                                            }
                                        });
                                    }
                                    ;
                                }
                            };
                        }
                        return {
                            name : "next-promise-2",
                            get then () : any {
                                log.push ({
                                    name : "get next then (2)",
                                    thisValue : this
                                });
                                return function (this : JSDynamicObject, resolve : any) : any {
                                    log.push ({
                                        name : "call next then (2)",
                                        thisValue : this,
                                        args : [ ... JSarguments]
                                    });
                                    resolve ({
                                        name : "next-result-2",
                                        get value () : string {
                                            log.push ({
                                                name : "get next value (2)",
                                                thisValue : this
                                            });
                                            return "next-value-2";
                                        },
                                        get done () : boolean {
                                            log.push ({
                                                name : "get next done (2)",
                                                thisValue : this
                                            });
                                            return true;
                                        }
                                    });
                                }
                                ;
                            }
                        };
                    }
                    ;
                }
            };
        }
        ;
    }
};
